package View;

import Controller.PointController;
import Model.Camera;
import Model.Point;
import Model.Scenario;
import java.util.ArrayList;
import java.util.Collections;
import javax.swing.table.AbstractTableModel;

/*
 * ScenarioTableModel.java
 * ScenarioTableModel class lets to separate table manipulation logic from
 * SubEditor panel
 * @author V3nom
 * Created on 2011-05-31, 15.32.40
 */
public class ScenarioTableModel extends AbstractTableModel {

    private ArrayList<Point> pointsList;
    private PointController controller;
    private Scenario scenario;
    private Camera camera;
    //Column name constants
    private static final String ALIAS = "Alias";
    private static final String TIME_FROM_START = "Time from start";
    private static final String POS_X = "Position X";
    private static final String POS_Y = "Position Y";
    private static final String POS_Z = "Position Z";
    private static final String TILT_POS = "Tilt position";
    private static final String SLIDE_POS = "Slide position";
    private static final String CRANE_POS_X = "Crane position X";
    private static final String CRANE_POS_Y = "Crane position Y";
    private String[] columnNames;

    public ScenarioTableModel(Camera camera, Scenario scenario) {
        this.camera = camera;
        this.scenario = scenario;
        pointsList = new ArrayList<Point>();
        columnNames = new String[]{ALIAS, TIME_FROM_START, POS_X, POS_Y, POS_Z,
            TILT_POS, SLIDE_POS, CRANE_POS_X, CRANE_POS_Y};
        controller = new PointController();
    }

    @Override
    public int getRowCount() {
        return pointsList.size();
    }

    @Override
    public int getColumnCount() {
        return columnNames.length;
    }

    @Override
    public String getColumnName(int column) {
        return columnNames[column];
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Point point = pointsList.get(rowIndex);
        String value = "";
        switch (columnIndex) {
            case 0:
                value = point.getAlias();
                break;
            case 1:
                value = "" + point.getTimeFromStart();
                break;
            case 2:
                value = "" + point.getPosX();
                break;
            case 3:
                value = "" + point.getPosY();
                break;
            case 4:
                value = "" + point.getPosZ();
                break;
            case 5:
                value = "" + point.getTiltPos();
                break;
            case 6:
                value = "" + point.getSlidePos();
                break;
            case 7:
                value = "" + point.getCranePosX();
                break;
            case 8:
                value = "" + point.getCranePosY();
                break;
        }
        return value;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return true;
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        Point point = pointsList.get(rowIndex);
        int number = 0;
        if (columnIndex > 0) {
            if (validateNumber(aValue.toString())) {

                number = Integer.parseInt(aValue.toString());
                switch (columnIndex) {
                    case 1: {
                        point.setTimeFromStart(number);
                    }
                    break;
                    case 2:
                        point.setPosX(checkBoundaries(number, camera.getPosXMax(), camera.getPosXMin()));
                        break;
                    case 3:
                        point.setPosY(checkBoundaries(number, camera.getPosYMax(), camera.getPosYMin()));
                        break;
                    case 4:
                        point.setPosZ(checkBoundaries(number, camera.getPosZMax(), camera.getPosZMin()));
                        break;
                    case 5:
                        point.setTiltPos(checkBoundaries(number, camera.getTiltPosMax(), camera.getTiltPosMin()));
                        break;
                    case 6:
                        point.setSlidePos(checkBoundaries(number, camera.getSlidePosMax(), camera.getSlidePosMin()));
                        break;
                    case 7:
                        point.setCranePosX(checkBoundaries(number, camera.getCranePosXMax(), camera.getCranePosXMin()));
                        break;
                    case 8:
                        point.setCranePosY(checkBoundaries(number, camera.getCranePosYMax(), camera.getCranePosYMin()));
                        break;
                }
            }
        } else {
            point.setAlias(aValue.toString());
        }

        controller.savePoint(point, scenario);
        sortList();
        this.fireTableDataChanged();
    }
    /*
     * Ask point controller for new Point object and adds it to the table. Also
     * saves this new point to the database
     */

    public void addNewPoint() {
        Point newPoint = controller.createPoint();
        newPoint.setAlias("NewPoint1");
        newPoint.setCamera(camera);
        pointsList.add(newPoint);
        controller.savePoint(newPoint, scenario);
        this.fireTableDataChanged();
    }

    /*
     * Calls point controller to delete selected point from the database
     */
    public void deletePoint(int columnIndex) {
        controller.deletePoint(pointsList.remove(columnIndex));
        sortList();
        this.fireTableDataChanged();
    }

    /*
     * Adds existing point to the table
     */
    public void addPoint(Point point) {
        pointsList.add(point);
        sortList();
        this.fireTableDataChanged();
    }

    /*
     * Asks point controller to delete all points in the table from the database
     */
    public void deleteAllPoints() {
        for (Point point : pointsList) {
            controller.deletePoint(point);
        }
    }

    /*
     * Sorts point table by time from start
     */
    private void sortList() {
        Collections.sort(pointsList);
    }

    /*
     * Returns all points from table
     */
    public ArrayList<Point> getPointsList() {
        return pointsList;
    }

    private boolean validateNumber(String input) {
        try {
            Integer.parseInt(input);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private int checkBoundaries(int value, int max, int min) {
        if (value < min) {
            return min;
        } else if (value > max) {
            return max;
        }

        return value;
    }
}
